package com.zds.support.manager

import android.text.TextUtils
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.trello.rxlifecycle3.android.lifecycle.kotlin.bindUntilEvent
import com.zds.support.api.resp.LoginResp
import com.zds.support.util.AppUtils
import com.zds.support.util.LogUtils
import com.zds.support.util.PreferenceUtils
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers

class CacheManager {
    companion object {
        private const val CACHE_PREFERENCES_FILE_NAME = "essy_cache"
        private const val KEY_USER_INFO = ""

        @JvmStatic
        val instance: CacheManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            CacheManager()
        }
    }

    private constructor() {

    }

    var userInfoCache: LoginResp? = null

    fun saveUserInfo(userInfo: LoginResp) {
        userInfoCache = userInfo
    }

    fun getUserInfo(onSuccessListener: (result: LoginResp) -> Unit) {
        getData(KEY_USER_INFO, object : TypeToken<LoginResp>() {},
                { r ->
                    userInfoCache = r
                    onSuccessListener.invoke(r)
                })
    }


    fun <T> saveData(data: T, key: String) {
        saveData(data, key, {})
    }

    fun <T> saveData(data: T, key: String, onSuccessListener: () -> Unit) {
        Observable.just(data)
                .map { t: T ->
                    val json = Gson().toJson(t)
                    PreferenceUtils.putString(
                            AppUtils.appContext, CACHE_PREFERENCES_FILE_NAME,
                            key, json
                    )
                }
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({ onSuccessListener.invoke() }, { t: Throwable? -> })
    }

    fun <T> getDataSync(key: String, defaultValue: String, typeToken: TypeToken<T>): T? {
        val json = PreferenceUtils.getString(
                AppUtils.appContext, CACHE_PREFERENCES_FILE_NAME,
                key, defaultValue
        )
        var t: T?
        if (!TextUtils.isEmpty(json)) {
            try {
                t = Gson().fromJson(json, typeToken.type)
                t
            } catch (e: Exception) {
                throw  e
            }
        }
        return null
    }

    fun <T> getData(key: String, defaultValue: String, typeToken: TypeToken<T>, onSuccessListener: (result: T) -> Unit,
                    onFailListener: (() -> Unit)? = null) {

        Observable.just(key)
                .map { keyFinal: String ->
                    var t: T?
                    val json = PreferenceUtils.getString(
                            AppUtils.appContext, CACHE_PREFERENCES_FILE_NAME,
                            keyFinal, defaultValue
                    )
                    if (!TextUtils.isEmpty(json)) {
                        try {
                            t = Gson().fromJson(json, typeToken.type)
                            return@map t
                        } catch (e: Exception) {
                            throw  e
                        }
                    }
                    throw  NullPointerException("no cache")
                }
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({ t: T? ->
                    if (t != null) {
                        onSuccessListener.invoke(t)
                    }

                }, { t: Throwable? ->
                    if (onFailListener != null) {
                        onFailListener.invoke()
                    }
                })
    }

    fun <T> getData(key: String, typeToken: TypeToken<T>, onSuccessListener: (result: T) -> Unit) {
        getData(key, "", typeToken, onSuccessListener)
    }

    fun <T> getArrayDataSync(key: String, typeToken: TypeToken<ArrayList<T>>): ArrayList<T> {
        val data = ArrayList<T>()
        val json = PreferenceUtils.getString(
                AppUtils.appContext, CACHE_PREFERENCES_FILE_NAME,
                key, "")
        if (!TextUtils.isEmpty(json)) {
            try {
                data.addAll(Gson().fromJson(json, typeToken.type))
            } catch (e: Exception) {
            }
        }
        return data
    }

    fun <T> getArrayData(key: String, typeToken: TypeToken<ArrayList<T>>,
                         onSuccessListener: (result: ArrayList<T>) -> Unit,
                         lifecycleOwner: LifecycleOwner? = null) {
        val data = ArrayList<T>()
        val ob = Observable.just(key)
                .map { keyFinal: String ->
                    var tmp = ArrayList<T>()
                    val json = PreferenceUtils.getString(
                            AppUtils.appContext, CACHE_PREFERENCES_FILE_NAME,
                            keyFinal, ""
                    )
                    if (!TextUtils.isEmpty(json)) {
                        try {
                            tmp.addAll(Gson().fromJson(json, typeToken.type))
                        } catch (e: Exception) {
                        }
                    }
                    tmp
                }
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())

        if (lifecycleOwner != null) {
            ob.bindUntilEvent(lifecycleOwner, Lifecycle.Event.ON_DESTROY)
        }
        ob.subscribe({ t: ArrayList<T>? ->
            if (t != null) {
                data.addAll(t)
            }
            onSuccessListener.invoke(data)
        }, { t: Throwable? ->
            LogUtils.d("CacheManager", "getArrayData error->${t?.localizedMessage}")
            t?.printStackTrace()
        })
    }

    fun removeKey(key: String) {
        PreferenceUtils.removeKey(
                AppUtils.appContext, CACHE_PREFERENCES_FILE_NAME,
                key
        )
    }


    fun clearUserInfo() {
    }



}